package com.jgzx.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.*;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.jgzx.utils.AppContextUtil;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.reflection.property.PropertyNamer;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 基础Service
 * @author libo
 * @date 2021/4/6 10:14
 */
public class BaseServiceImpl<M extends BaseMapper<T>, T> extends AbstractServiceImpl<M, T, SFunction<T, ?>>{

    @Override
    protected boolean saveBatchByDetail(List<T> entityList, String hidField, Long hid, boolean isEnableEnterprise, int batchSize) {
        List<Long> delIds = getDelDetailId(entityList, hidField, hid, isEnableEnterprise);
        /* 通过主键进行新增、更新 */
        TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
        Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!");
        String keyProperty = tableInfo.getKeyProperty();
        Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!");
        if (CollUtil.isNotEmpty(delIds)) {
            if (!SqlHelper.retBool(baseMapper.deleteBatchIds(delIds))) {
                return false;
            }
        }
        return SqlHelper.saveOrUpdateBatch(this.entityClass, this.mapperClass, this.log, entityList, batchSize, (sqlSession, entity) -> {
            Object idVal = ReflectionKit.getFieldValue(entity, keyProperty);
            return StringUtils.checkValNull(idVal)
                    || CollectionUtils.isEmpty(sqlSession.selectList(getSqlStatement(SqlMethod.SELECT_BY_ID), entity));
        }, (sqlSession, entity) -> {
            MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
            param.put(Constants.ENTITY, entity);
            sqlSession.update(getSqlStatement(SqlMethod.UPDATE_BY_ID), param);
        });
    }


    @Override
    protected List<Long> getDelDetailId(List<T> entityList, String hidField, Long hid, boolean isEnableEnterprise) {
        List<T> delDetailList = getDelDetailList(entityList, hidField, hid, isEnableEnterprise);
        return delDetailList.stream().map(del -> (Long) ReflectionKit.getFieldValue(del, getKeyProperty())).collect(Collectors.toList());
    }

    @Override
    protected List<T> getDelDetailList(List<T> entityList, String hidField, Long hid, boolean isEnableEnterprise) {
        List<T> delDetailList = new ArrayList<>();
        /*
         * 2.查询hid下的所有数据库数据集合
         */
        QueryWrapper<T> wrapper = new QueryWrapper<>();
        if (isEnableEnterprise) {
            wrapper.eq("enterprise_id", AppContextUtil.getEnterpriseId());
        }
        wrapper.eq(hidField, hid);
        List<T> alreadyEntityList = baseMapper.selectList(wrapper);
        /*
         * 3.记录删除明细主键
         */
        for (T alreadyEntity : alreadyEntityList) {
            Long id = (Long) ReflectionKit.getFieldValue(alreadyEntity, getKeyProperty());
            boolean isExists = false;
            if (CollUtil.isNotEmpty(entityList)) {
                for (T entity : entityList) {
                    if (id.equals(ReflectionKit.getFieldValue(entity, getKeyProperty()))) {
                        isExists = true;
                    }
                }
            }
            if (!isExists) {
                delDetailList.add(alreadyEntity);
            }
        }
        return delDetailList;
    }


    @Override
    protected String columnToString(SFunction<T, ?> column) {
        SerializedLambda lambda = LambdaUtils.resolve(column);
        String fieldName = PropertyNamer.methodToProperty(lambda.getImplMethodName());
        TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
        TableFieldInfo tableFieldInfo = tableInfo.getFieldList().stream().filter(field -> field.getProperty().equals(fieldName)).findAny().orElse(null);
        if (tableFieldInfo == null) {
            return null;
        }
        return tableFieldInfo.getColumn();
    }

}
